import { defineDirectiveNamed } from "@/shared/define.js";

class SuspenseService {}
/**
 * @implements {ng.IController}
 */
class SuspenseController {
  static $inject = [
    "$scope",
    "$element",
    "$attrs",
    "$transclude",
    "$templateCache",
    "$q",
  ];

  /**
   * @param {ng.IScope} $scope
   * @param {HTMLElement} $element
   * @param {ng.IAttributes} $attrs
   * @param {ng.ITranscludeFunction} $transclude
   * @param {ng.ITemplateCacheService} $templateCache
   * @param {ng.IQService} $q
   */
  constructor($scope, $element, $attrs, $transclude, $templateCache, $q) {
    this.$scope = $scope;
    this.$element = $element;
    this.$attrs = $attrs;
    this.$transclude = $transclude;
    this.$templateCache = $templateCache;
    this.$q = $q;
    // assign slot-config
    Object.assign(this.#slots, this.#computedHasSlot());
  }

  /**
   * @type {{ default: boolean; fallback: boolean; error: boolean; }}
   */
  #slots = {
    default: false,
    fallback: false,
    error: false,
  };

  /**
   * @member state
   * @type {boolean}
   */
  state = false;

  #computedHasSlot() {
    /** @type {Record<string, boolean>} */
    const s = {};
    for (const i in this.$transclude.$$boundTransclude.$$slots) {
      /** @type {function | undefined} */
      const slotHasDefined = this.$transclude.$$boundTransclude.$$slots[i];
      if (slotHasDefined) {
        s[i] = true;
      }
    }
    return s;
  }

  $onInit() {}

  /**
   * @param {Error | null} error
   * @param {undefined=} source
   * @returns {void}
   */
  catchError(error, source) {
    if (this.#slots.error) {
      this.$q.reject(error);
    }
  }

  $onSuspenseStart() {}

  $onSuspenseSuccess() {}

  handleClick() {
    console.log("NgSuspense", this);
  }
}

const NgSuspense = /* #__PURE__ */ defineDirectiveNamed(
  "ng-suspense",
  /**
   * @param {ng.auto.IInjectorService} $injector
   * @param {ng.IQService} $q
   * @returns {ng.IDirective}
   */
  ($injector, $q) => ({
    restrict: "E",
    controller: SuspenseController,
    controllerAs: "$suspense",
    // require: {
    //   suspense: "^suspense",
    // },
    bindToController: {
      // 可以引用其他的dom片段
      fallback: "@?",
    },
    transclude: {
      fallback: "suspenseFallback",
      default: "suspenseDefault",
      error: "?suspenseError",
    },
    // IDirectiveLinkFn
    // link(scope, el, attr, ctrl, transclude) {
    //   console.log("Suspense", scope);
    //   console.log("Suspense", el);
    //   console.log("Suspense", attr);
    //   console.log("Suspense", ctrl);
    //   // console.log("Suspense", transclude);
    // },
    template: html`
      <div>
        <ng-transclude
          class="ng-transclude-fallback"
          ng-if="$suspense.slots.fallback"
          ng-transclude-slot="fallback"
        ></ng-transclude>
        <ng-transclude
          class="ng-transclude-default"
          ng-if="$suspense.slots.default"
          ng-transclude-slot="default"
        ></ng-transclude>
      </div>
    `,
  }),
  ["$injector"],
);

export default NgSuspense;
